﻿using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using Microsoft.VisualStudio.TestTools.LoadTesting;
using CustomLoadProfiles;

namespace TestProject1
{
    // This plug-in references classes created in CustomLoadProfiles.dll, which is part of the solution
    // Details can also be found in http://blogs.msdn.com/yutong/archive/2010/04/02/load-test-plug-in-simulate-peak-load-modeling.aspx
    // The properties of the plug-in can be configured in the Add Load Test Plug-in dialog
    [Description("This plug-in simulates the Peak user load Pattern every 3 minutes")]
    public class PeakLoadModelingPlugin : ILoadTestPlugin
    {
        public void Initialize(LoadTest loadTest)
        {
            m_loadTest = loadTest;
            m_profileManager = new LoadProfileManager();

            // The heartbeat event will be fired every second, it can be used to adjust the user load
            m_loadTest.Heartbeat += new EventHandler<HeartbeatEventArgs>(m_loadTest_Heartbeat);

            // Create the custom load pattern based on the configurations passed through the plug-in properties
            CreateLoadProfileGroups();
        }

        // Create a custom user load profile group: Valley-StepUp-Peak-StepDown
        void CreateLoadProfileGroups()
        {
            // Create the custom load pattern group
            // Calculate the duration
            // If the RepeatCount for the Peak Load pattern is not specified, check the PercentageOfDuration, and calculate
            int patternDuration = 0;
            if (RepeatCount == 0)
            {
                double patternDurationInDouble = m_loadTest.RunSettings.RunDuration * PercentageOfDuration / 100;
                patternDuration = (Int32)Math.Ceiling(patternDurationInDouble);
            }
            else
            {
                patternDuration = (ValleyTime + RampUpTime + PeakTime + RampDownTime) * RepeatCount;
            }

            LoadProfileGroup profileGroup = new LoadProfileGroup("Valley-StepUp-Peak-StepDown", patternDuration);

            // Add the load profiles to a group
            // The step duration 5 seconds will be used to simulate the step up/down
            int stepDuration = 5;

            // 1. Simulate the ValleyLoad for a duration of ValleyTime
            profileGroup.AddProfile(new ConstLoadWrapper(ValleyLoad, ValleyTime));

            // 2. Simulate step up load - step up from ValleyLoad to PeakLoad in the RampUpTime window
            double stepCount = Math.Round((double)(PeakLoad - ValleyLoad) * stepDuration / RampUpTime);
            profileGroup.AddProfile(new StepLoadWrapper(ValleyLoad, ValleyLoad, PeakLoad, (int)stepCount, stepDuration, 0, RampUpTime));

            // 3. Simulate Peakload for PeakTime
            profileGroup.AddProfile(new ConstLoadWrapper(PeakLoad, PeakTime));

            // 4. Simulate step down load - step down from PeakLoad to ValleyLoad in the RampDownTime window
            stepCount = Math.Round((double)(PeakLoad - ValleyLoad) * stepDuration / RampDownTime);
            CustomLoadWrapper profileWrapper = new CustomLoadWrapper(RampDownTime);
            profileWrapper.Profile = new LoadTestStepDownLoadProfile(PeakLoad, ValleyLoad, PeakLoad, (int)stepCount, stepDuration);
            profileGroup.AddProfile(profileWrapper);

            // Add the profile group 
            m_profileManager.ProfileGroups.Add(profileGroup);

            // Tell the profile manager that we want to simulate the custom pattern right after test run is started
            m_profileManager.SetStartEndTimeForProfileGroups(0);
        }

        // The following heartbeat event will be fired every second, it can be used to adjust the user load
        void m_loadTest_Heartbeat(object sender, HeartbeatEventArgs e)
        {
            if (!e.IsWarmupComplete)
            {
                return;
            }

            // Get the load profile to be applied for the event
            LoadTestLoadProfile profile = m_profileManager.GetCurrentLoadProfile(e.ElapsedSeconds, m_loadTest.Scenarios[0].CurrentLoad);
            if (profile != null)
            {
                m_loadTest.Scenarios[0].LoadProfile = profile;
            }
        }

        #region Load Profile Configurations
        [DefaultValue(20)]
        [Description("The Valley Load")]
        public int ValleyLoad
        {
            get { return m_valleyLoad; }
            set { m_valleyLoad = value; }
        }

        [DefaultValue(20)]
        [Description("The Peak Load")]
        public int PeakLoad
        {
            get { return m_peakLoad; }
            set { m_peakLoad = value; }
        }

        [DefaultValue(60)]
        [Description("The amount of time that ValleyLoad will be simulated")]
        public int ValleyTime
        {
            get { return m_valleyTime; }
            set { m_valleyTime = value; }
        }

        [DefaultValue(60)]
        [Description("The amount of time that PeakLoad will be simulated")]
        public int PeakTime
        {
            get { return m_peakTime; }
            set { m_peakTime = value; }
        }

        [DefaultValue(20)]
        [Description("The amount of time to ramp up from ValleyLoad to PeakLoad")]
        public int RampUpTime
        {
            get { return m_rampUpTime; }
            set { m_rampUpTime = value; }
        }

        [DefaultValue(20)]
        [Description("The amount of time to step down from PeakLoad to ValleyLoad")]
        public int RampDownTime
        {
            get { return m_rampDownTime; }
            set { m_rampDownTime = value; }
        }

        [DefaultValue(20)]
        [Description("The number of times to repeat this pattern")]
        public int RepeatCount
        {
            get { return m_repeatCount; }
            set { m_repeatCount = value; }
        }

        [DefaultValue(100)]
        [Description("When the RepeatCount is 0. This property specifies the % of the duration that the pattern will be simulated. Default to entire duration")]
        public int PercentageOfDuration
        {
            get { return m_percentageOfDuration; }
            set { m_percentageOfDuration = value; }
        }

        #endregion

        private LoadTest m_loadTest;
        private LoadProfileManager m_profileManager;

        private int m_valleyLoad;
        private int m_peakLoad;

        private int m_valleyTime;
        private int m_peakTime;
        private int m_rampUpTime;
        private int m_rampDownTime;

        private int m_repeatCount;
        private int m_percentageOfDuration;
    }
}
